﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using Facebook;
using System.Text;
using System.Net.Mail;
using System.Net;

namespace WebSocialKiller
{
    /// <summary>
    /// Description résumée de ServiceSocialKiller
    /// </summary>
    [WebService(Namespace = "http://www.socialkiller.fr/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // Pour autoriser l'appel de ce service Web depuis un script à l'aide d'ASP.NET AJAX, supprimez les marques de commentaire de la ligne suivante. 
    [System.Web.Script.Services.ScriptService]
    public class ServiceSocialKiller : System.Web.Services.WebService
    {

        [WebMethod]
        public int monTest()
        {
            return 123456;
        }
        [WebMethod]
        public long connexion(string _token)
        {
            long retour = -1;
            dynamic result;

            try
            {
                Console.WriteLine("tentative de connexion");
                var fb = new FacebookClient(_token);
                result = fb.Get("me");

                List<UserFacebook> friends = new List<UserFacebook>();
                foreach (dynamic friend in (JsonArray)((JsonObject)fb.Get("me/friends"))["data"])
                {
                    UserFacebook f = new UserFacebook(friend.id, friend.name);
                    friends.Add(f);
                }
                UserFacebook userFacebook = new UserFacebook(result.id, result.name, friends.ToArray());
                

                socialkillerEntities Context = new socialkillerEntities();
                addUser(Context, userFacebook.id, userFacebook.name);
                var userDetailList = Context.user_detail.Where(p => p.id == userFacebook.id);
                if (userDetailList.Count() == 0)
                {
                    Context.user_detail.AddObject(new user_detail { id = userFacebook.id, longitude = -1, latitude = -1, score = 0, id_weapon = 1, email = result.email });
                    Context.SaveChanges();
                }
                foreach (UserFacebook u in userFacebook.friends)
                {
                    addUser(Context, u.id, u.name);
                }
                List<long> contextFriendsLong = (List<long>)Context.links.Where(p => p.user1 == userFacebook.id).Select(p => p.user2).ToList();
                List<long> facebookFriendsLong = (List<long>)userFacebook.friends.Select(p => p.id).ToList();
                List<long> newFriendsLong = facebookFriendsLong.Except(contextFriendsLong).ToList();
                List<UserFacebook> newFriendsF = new List<UserFacebook>();
                foreach (long f in newFriendsLong)
                {
                    newFriendsF.Add((UserFacebook)userFacebook.friends.Where(p => p.id == f).First());
                }
                foreach (long f in newFriendsF.Select(p => p.id))
                {
                    Context.links.AddObject(new link { user1 = userFacebook.id, user2 = f });
                }
                Context.SaveChanges();

                retour = userFacebook.id;
                Console.WriteLine("connexion succes");
            }
            catch (Exception)
            {
                Console.WriteLine("connexion fail");
                retour = -1;
            }


            return retour;
        }


        public string addUser(socialkillerEntities _context, long _id, string _name)
        {

            var users = _context.users.Where(p => p.id == _id);
            if (users.Count() == 0)
            {
                _context.users.AddObject(new user { id = _id, name = _name });
            }
            return "0";
        }

        [WebMethod]
        public string setCoordonates(long _idUser, float _longitude, float _latitude)
        {
            socialkillerEntities Context = new socialkillerEntities();
            var userDetailList = Context.user_detail.Where(p => p.id == _idUser);
            if (userDetailList.Count() == 0)
            {
                Context.user_detail.AddObject(new user_detail { id = _idUser, longitude = _longitude, latitude = _latitude, score = 0, id_weapon = 1 });
            }
            else
            {
                if (_longitude != -1 && _latitude != -1)
                {
                    var userDetail = userDetailList.First();
                    userDetail.longitude = _longitude;
                    userDetail.latitude = _latitude;
                }
            }
            Context.SaveChanges();
            return "0";
        }

        [WebMethod]
        public string[] getFight(long _idUser)
        {
            List<string> retour = new List<string>();
            socialkillerEntities Context = new socialkillerEntities();
            long nbTarget = 0;
            user_detail target = null;
            fight fightIns = null;
            int cpt = 0;
            while (nbTarget == 0 && cpt < 10)
            {
                var targetList = Context.fights.Where(p => p.killer == _idUser && p.state == 0);
                nbTarget = targetList.Count();
                if (nbTarget == 0)
                {
                    var yetTargeted = Context.fights.Where(p => p.killer == _idUser && p.state != 0).Select(p => p.target);
                    var myKiller = Context.fights.Where(p => p.target == _idUser && p.state == 0).Select(p => p.target);
                    List<long> me = new List<long>();
                    me.Add(_idUser);
                    List<long> candidateList = Context.user_detail.Select(p => p.id).Except(yetTargeted).Except(myKiller).Except(me).ToList();
                    long candidate = candidateList[(int)new Random().Next(candidateList.Count)];

                    Context.fights.AddObject(new fight { killer = _idUser, killer_score = 0, target = candidate, target_score = 0, date_expiration = DateTime.Now, state = 0 });
                    Context.SaveChanges();
                }
                else
                {
                    if (targetList.First().date_expiration < DateTime.Now.AddDays(-1))
                    {
                        Context.fights.DeleteObject(targetList.First());
                        Context.SaveChanges();
                    }
                    else
                    {
                        target = targetList.First().user_detail1;
                        fightIns = targetList.First();
                    }
                }
                targetList = Context.fights.Where(p => p.killer == _idUser && p.state == 0);
                nbTarget = targetList.Count();
                cpt++;
            }
            if (nbTarget != 0 && fightIns != null)
            {
                updateMyScore(fightIns.killer);
                updateMyScore(fightIns.target);
                retour.Add(fightIns.id.ToString()); //id du combat
                retour.Add(fightIns.killer.ToString()); //id de l'assassin
                retour.Add(fightIns.user_detail.user.name.ToString()); //nom de l'assassin
                retour.Add(fightIns.killer_score.ToString()); //score de l'assassin
                retour.Add(fightIns.target.ToString());// id de la cible
                retour.Add(fightIns.user_detail1.user.name.ToString());//nom de la cible
                retour.Add(fightIns.target_score.ToString());//score dans le combat de la cible
                retour.Add(getClassement(fightIns.target).ToString());//classement de la cible
                retour.Add(Context.fights.Where(p => p.killer == fightIns.target && p.state == 1).Count().ToString());//nombre de victime de la cible
                retour.Add(fightIns.user_detail1.longitude.ToString());//longitude de la cible
                retour.Add(fightIns.user_detail1.latitude.ToString());//latitude de la cible
                retour.Add(fightIns.user_detail1.score.ToString());//score de la cible
            }
            else
            {
                retour.Add("-1"); //id du combat
                retour.Add("-1"); //id de l'assassin
                retour.Add("inconnu"); //nom de l'assassin
                retour.Add("-1"); //score de l'assassin
                retour.Add("-1");// id de la cible
                retour.Add("inconnu");//nom de la cible
                retour.Add("-1");//score dans le combat de la cible
                retour.Add("-1");//classement de la cible
                retour.Add("-1");//nombre de victime de la cible
                retour.Add("-1");//longitude de la cible
                retour.Add("-1");//latitude de la cible
                retour.Add("-1");//score de la cible
            }

            return retour.ToArray();
        }

        [WebMethod]
        public String[] getStringArray()
        {
            List<String> retour = new List<string>();
            retour.Add("-1"); //id du combat
            retour.Add("-1"); //id de l'assassin
            retour.Add("inconnu"); //nom de l'assassin
            retour.Add("-1"); //score de l'assassin
            retour.Add("-1");// id de la cible
            retour.Add("inconnu");//nom de la cible
            retour.Add("-1");//score de la cible
            retour.Add("-1");//longitude de la cible
            retour.Add("-1");//latitude de la cible
            retour.Add("-1");//score de la cible
            retour.Add("-1");//classement de la cible
            return retour.ToArray();
        }

        public long getClassement(long _idUser)
        {
            long retour = -1;
            socialkillerEntities Context = new socialkillerEntities();
            var userDetailList = Context.user_detail.OrderByDescending(p => p.score);
            long cpt = 0;
            foreach (var u in userDetailList)
            {
                cpt++;
                if (_idUser == u.id)
                {
                    retour = cpt;
                    break;
                }
            }
            return retour;
        }



        [WebMethod]
        public string updateMyScore(long _idUser)
        {
            socialkillerEntities Context = new socialkillerEntities();
            var myFights = Context.fights.Where(p => p.killer == _idUser && p.state != 0);
            int newScore = 0;
            foreach (var myFight in myFights)
            {
                if (myFight.state == 1) //win
                {
                    newScore += victory(myFight.target);
                }
                if (myFight.state == -1) //lost
                {
                    newScore += defeat(myFight.killer);
                }
            }
            var sponsors = Context.sponsors.Where(p => p.userId == _idUser).Select(p => p.friendEmail);
            int goodSponsors = Context.user_detail.Select(p => p.email).Intersect(sponsors).Count();
            newScore += goodSponsors * 50;

            if (newScore < 0) newScore = 0;
            var me = Context.user_detail.Where(p => p.id == _idUser).First();
            me.score = newScore;
            Context.SaveChanges();
            return "0";
        }

        [WebMethod]
        public string[] getMe(string _idUser)
        {
            long idUser = Convert.ToInt64(_idUser);
            updateMyScore(idUser);
            updadeWeaponId(idUser);
            List<string> retour = new List<string>();
            socialkillerEntities Context = new socialkillerEntities();
            string id = _idUser.ToString();
            string name = Context.users.Where(p => p.id == idUser).First().name;
            var detail_user = Context.user_detail.Where(p => p.id == idUser).First();
            string longitude = detail_user.longitude.ToString();
            string latitude = detail_user.latitude.ToString();
            string score = detail_user.score.ToString();
            string classement = getClassement(idUser).ToString();
            string nbDeath = Context.fights.Where(p => p.target == idUser && p.state == 1).Count().ToString();
            string nbVictory = Context.fights.Where(p => p.killer == idUser && p.state == 1).Count().ToString();
            string weaponId = detail_user.id_weapon.ToString();
            string weaponName = detail_user.weapon.name;

            retour.Add(id); //id de l'utilisateur
            retour.Add(name); //nom de l'utilisateur
            retour.Add(longitude); //longitude de l'utilisateur
            retour.Add(latitude); //latitude de l'utilisateur
            retour.Add(score); //score de l'utilisateur
            retour.Add(classement); //classement de l'utilisateur
            retour.Add(nbVictory); //nb victoire de l'utilisateur
            retour.Add(nbDeath); //nb mort de l'utilisateur
            retour.Add(weaponId); //numéro de l'arme de l'utilisateur
            retour.Add(weaponName); //nom de l'arme de l'utilisateur

            return retour.ToArray();
        }

        [WebMethod]
        public bool checkAttack(long _idUser)
        {
            return (new socialkillerEntities().fights.Where(p => p.target == _idUser && p.state == 0 && p.killer_score != 0).Count() != 0);
        }

        [WebMethod]
        public string attack(long _idUser, int _point)
        {
            socialkillerEntities Context = new socialkillerEntities();
            var fightNow = Context.fights.Where(p => p.killer == _idUser && p.state == 0 && p.killer_score == 0).First();
            updadeWeaponId(_idUser);
            fightNow.killer_score = _point - (int)Context.user_detail.Where(p => p.id == _idUser).First().weapon.power;
            fightNow.date_expiration = DateTime.Now;
            Context.SaveChanges();
            return "0";
        }

        [WebMethod]
        public int defend(long _idUser, int _point)
        {
            int retour = 0;
            socialkillerEntities Context = new socialkillerEntities();
            var fightNow = Context.fights.Where(p => p.target == _idUser && p.state == 0 && p.killer_score != 0).First();
            updadeWeaponId(_idUser);
            fightNow.target_score = _point - (int)Context.user_detail.Where(p => p.id == _idUser).First().weapon.power;
            if (fightNow.killer_score < _point)
            {
                fightNow.state = 1;
                retour = 1; //la victime a perdu
            }
            else
            {
                fightNow.state = -2;
                fightNow.killer_score = 0;
                fightNow.target_score = 0;
                retour = -2; //la victime a gagné
            }
            Context.SaveChanges();
            return retour;
        }

        [WebMethod]
        public string[] getFightState(long _idFight)
        {
            List<string> retour = new List<string>();

            socialkillerEntities Context = new socialkillerEntities();
            var fight = Context.fights.Where(p => p.id == _idFight).First();
            retour.Add(fight.state.ToString());

            if (retour[0] == "0")//la cible ne s'est pas encore défendu
            {
                if (DateTime.Now.AddHours(-1) > fight.date_expiration) //expiration
                {
                    fight.state = 1;
                    retour[0] = fight.state.ToString();
                }
            }

            if (retour[0] == "1")
            {
                //<take the target of this target?>
                var anotherFight = Context.fights.Where(p => p.killer == fight.target).First();
                long possibleNewTarget = anotherFight.target;
                bool takeFight = Context.links.Where(p => p.user1 == fight.killer && p.user2 == possibleNewTarget).Count() != 0;

                if (takeFight)
                {
                    anotherFight.killer = fight.killer;
                    anotherFight.killer_score = 0;
                    anotherFight.date_expiration = DateTime.Now;
                    Context.SaveChanges();
                }
                //</take the target of this target?>
            }
            if (retour[0] == "-2")
            {
                Context.fights.AddObject(new fight { killer = fight.killer, killer_score = 0, target = fight.target, target_score = 0, date_expiration = DateTime.Now, state = 0 });
                Context.SaveChanges();
            }

            retour.Add(fight.killer_score.ToString());
            return retour.ToArray();
        }

        [WebMethod]
        public int getProximite(long _idFight)
        {
            int retour = 0;
            try
            {
                socialkillerEntities Context = new socialkillerEntities();
                var fight = Context.fights.Where(p => p.id == _idFight).First();
                DateTime naow = DateTime.Now.AddMinutes(-30);
                bool invicible = Context.fights.Where(p => p.killer == fight.target && (p.state == -2 || p.state == -1) && naow < p.date_expiration).Count() != 0;
                if (invicible || Context.fights.Where(p => p.killer_score != 0 && p.id == _idFight).Count() != 0)
                {
                    retour = -1;
                }
                else
                {

                    double longitude_killer = fight.user_detail.longitude;
                    double latitude_killer = fight.user_detail.latitude;
                    double longitude_target = fight.user_detail1.longitude;
                    double latitude_target = fight.user_detail1.latitude;
                    double earth_radius = 6378137;   // Terre = sphère de 6378km de rayon
                    double rlo1 = deg2rad(longitude_killer);
                    double rla1 = deg2rad(latitude_killer);
                    double rlo2 = deg2rad(longitude_target);
                    double rla2 = deg2rad(latitude_target);
                    double dlo = (rlo2 - rlo1) / 2;
                    double dla = (rla2 - rla1) / 2;
                    double a = (Math.Sin(dla) * Math.Sin(dla)) + Math.Cos(rla1) * Math.Cos(rla2) * (Math.Sin(dlo) * Math.Sin(dlo));
                    double d = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
                    if ((earth_radius * d) < 1000)
                    {
                        retour = 1;
                    }
                }
                //retour = 1;
                //if (fight.target == 1316853531)
                //    retour = 0;
            }
            catch (Exception)
            {

                retour = 0;
            }
            return retour;
        }
        public double deg2rad(double _deg)
        {
            return Math.PI * (_deg) / 180;
        }

        [WebMethod]
        public string[] getClassement()
        {
            List<String> retour = new List<String>();

            socialkillerEntities Context = new socialkillerEntities();
            var userDetailList = Context.user_detail.OrderByDescending(p => p.score);
            retour.Add(userDetailList.Count().ToString()); //le nombre d'objet
            foreach (var u in userDetailList)
            {
                retour.Add(u.id.ToString()); //l'identifiant pour la photo
                retour.Add(u.user.name); //le nom
                retour.Add(u.score.ToString()); //les points
            }

            return retour.ToArray();
        }

        [WebMethod]
        public string[] getVictims(long _idUser)
        {
            List<String> retour = new List<String>();

            socialkillerEntities Context = new socialkillerEntities();
            var fightList = Context.fights.Where(p => p.killer == _idUser && p.state == 1);
            retour.Add(fightList.Count().ToString()); //le nombre d'objet
            foreach (var u in fightList)
            {
                retour.Add(u.user_detail1.id.ToString()); //l'identifiant pour la photo
                retour.Add(u.user_detail1.user.name); //le nom
                retour.Add(victory(u.target).ToString()); //les points
            }

            return retour.ToArray();
        }

        public int victory(long _idVictim)
        {
            int retour = 3;
            socialkillerEntities Context = new socialkillerEntities();
            int nbUser = Context.user_detail.Count();
            int positionVictime = (int)getClassement(_idVictim);
            return retour + nbUser - positionVictime;
        }
        public int defeat(long _idVictim)
        {
            return -3;
        }

        [WebMethod]
        public int sponsor(long _idUser, string _friendName, string _friendEmail)
        {
            socialkillerEntities Context = new socialkillerEntities();
            bool yetSponsored = Context.sponsors.Where(p => p.friendEmail == _friendEmail).Count() != 0;
            if (!yetSponsored)
            {
                Context.sponsors.AddObject(new sponsor { userId = _idUser, friendEmail = _friendEmail });
                string myName = Context.users.Where(p => p.id == _idUser).Select(p => p.name).First();
                string subject = myName + " vous invite a jouer à Social Killer avec votre téléphone Android et Facebook";
                string message = "Bonjour " + _friendName + " ! Rejoins moi sur Social Killer en installant l'APK joint à cet email !";


                mail(myName, _friendName, _friendEmail, subject, message);
            }
            Context.SaveChanges();
            return 0;
        }

        [WebMethod]
        public int mail(string _userName, string _friendName, string _friendEmail, string _subject, string _message)
        {
            try
            {
                MailAddress fromAddress = new MailAddress("assass2i.socialkiller@gmail.com", _userName);
                MailAddress toAddress = new MailAddress(_friendEmail, _friendName);
                const string fromPassword = "123Soleil";
                string subject = _subject;
                string body = _message;
                string fileName = "c:/SocialKiller.apk";

                SmtpClient smtp = new SmtpClient
                {
                    Host = "smtp.gmail.com",
                    Port = 587,
                    EnableSsl = true,
                    DeliveryMethod = SmtpDeliveryMethod.Network,
                    UseDefaultCredentials = false,
                    Credentials = new NetworkCredential(fromAddress.Address, fromPassword)
                };

                MailMessage message = new MailMessage(fromAddress, toAddress)
                {
                    Subject = subject,
                    Body = body
                };
                {
                    message.Attachments.Add(new Attachment(fileName));
                    smtp.Send(message);
                }
            }
            catch (Exception)
            {
                Console.WriteLine("Erreur dans l'envoi de l'email");
            }
            return 0;
        }

        public void updadeWeaponId(long _idUser)
        {
            socialkillerEntities Context = new socialkillerEntities();
            var thisUser = Context.user_detail.Where(p => p.id == _idUser).First();
            long score = thisUser.score;
            var weapons = Context.weapons.OrderBy(p => p.power);
            int rank = 1;
            foreach (weapon _weapon in weapons)
            {
                if (score + 1 >= rank)
                {
                    thisUser.id_weapon = _weapon.id;
                }
                else
                {
                    break;
                }
                rank *= 2500;
            }
            Context.SaveChanges();
        }

    }
}
